﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Cms.Application.WebFramework.Presenters;
using Cms.Domain;
using Cms.Tests.Unit.Application;
using Cms.Web.Framework.Infrastructure;
using Cms.Web.Framework.Infrastructure.Wrappers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Cms.Tests.Unit.WebFramework.Infrastructure
{
    [TestClass]
    public class RequestDetailsTests : BasePresenterTests
    {
        private RequestDetails _requestDetails;

        [TestMethod]
        public void RequestDetailConstructor_JustPassWithoutErrors_Success()
        {
            _requestDetails = CreateMock("http://fredium.dev", "/");
            Assert.AreEqual("http://fredium.dev/", _requestDetails.RequestedUrl);
        }

        [TestMethod]
        public void Controller_Initialized_Success()
        {
            _requestDetails = CreateMock("http://fredium.dev", "/");
            Assert.IsInstanceOfType(_requestDetails.Presenter, typeof(RequestDetailsPresenter));
        }

        [TestMethod]
        public void SiteRootUrl_CompleteUrl_ShowDomainOnly()
        {
            _requestDetails = CreateMock("http://fredium.dev/testfolder/subfolder/page.aspx", "/");
            Assert.AreEqual("fredium.dev", _requestDetails.SiteRootUrl);
            _requestDetails = CreateMock("http://www.anothertest.dev/application/", "/application");
            Assert.AreEqual("www.anothertest.dev/application", _requestDetails.SiteRootUrl);
        }

        [TestMethod]
        public void SiteRootUrl_PortExplicitlyStated_ShowDomainOnly()
        {
            _requestDetails = CreateMock("http://fredium.dev:80/testfolder/subfolder/page.aspx", "/");
            Assert.AreEqual("fredium.dev", _requestDetails.SiteRootUrl);
        }

        [TestMethod]
        public void SiteRootUrl_OtherPortThan80_ShowDomainAndPort()
        {
            _requestDetails = CreateMock("http://fredium.dev:8080/testfolder/subfolder/page.aspx", "/");
            Assert.AreEqual("fredium.dev:8080", _requestDetails.SiteRootUrl);
        }

        [TestMethod]
        public void FoldersAndPage_JustPage_NoDomainOrFoldersShown()
        {
            _requestDetails = CreateMock("http://www.fredium.dev/page.aspx", "/");
            Assert.AreEqual("page.aspx", _requestDetails.FoldersAndPage);
            _requestDetails = CreateMock("http://www.fredium.dev/Page.aspx", "/");
            Assert.AreEqual("Page.aspx", _requestDetails.FoldersAndPage);
            _requestDetails = CreateMock("http://www.fredium.dev/application/Page.aspx", "/application");
            Assert.AreEqual("Page.aspx", _requestDetails.FoldersAndPage);
        }

        [TestMethod]
        public void FoldersAndPage_BothPageSubfoldersAndQuerystring_BothShown()
        {
            _requestDetails = CreateMock("http://www.fredium.dev/a/b/c/d/page.aspx?v=0", "/");
            Assert.AreEqual("a/b/c/d/page.aspx", _requestDetails.FoldersAndPage);
        }

        [TestMethod]
        public void Protocol_UseHttp_Http()
        {
            _requestDetails = CreateMock("http://www.fredium.dev/a/b/c/d/page.aspx?v=0", "/");
            Assert.AreEqual("http://", _requestDetails.Protocol);
        }

        [TestMethod]
        public void Protocol_UseHttps_Https()
        {
            _requestDetails = CreateMock("https://www.fredium.dev/a/b/c/d/page.aspx?v=0", "/");
            Assert.AreEqual("https://", _requestDetails.Protocol);
        }

        [TestMethod]
        public void AdministratorID_NotLoggedIn_MinusOne()
        {
            Mock<ICmsIdentity> identityMock = new Mock<ICmsIdentity>();
            _requestDetails = CreateMock("https://www.fredium.dev/a/b/c/d/page.aspx?v=0", "/", identityMock.Object);
            Assert.AreEqual(-1, _requestDetails.AdministratorID);
        }

        [TestMethod]
        public void AdministratorID_LoggedIn_ShowID()
        {
            _requestDetails = CreateMock("https://fredium.dev", "/", InfrastructureTestsHelper.GetIdentity(666));
            Assert.AreEqual(666, _requestDetails.AdministratorID);
        }

        [TestMethod]
        public void AdministratorMustBeLoggedOut_HasCurrentSiteAndForceLogoutNotSet_False()
        {
            InitRepositoryFactoryMock();
            Site site = new Site();
            Administrator admin = new Administrator() { ID = 666, ForceLogout = false, CurrentSite = site };
            AdministratorRepositoryMock.Setup(a => a.GetAdministrator(666)).Returns(admin);
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("https://fredium.dev", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.IsFalse(_requestDetails.AdministratorMustBeLoggedOut);
        }

        [TestMethod]
        public void AdministratorMustBeLoggedOut_HasCurrentSiteAndForceLogoutIsSet_True()
        {
            InitRepositoryFactoryMock();
            Site site = new Site();
            Administrator admin = new Administrator() { ID = 666, ForceLogout = true, CurrentSite = site };
            AdministratorRepositoryMock.Setup(a => a.GetAdministrator(666)).Returns(admin);
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("https://fredium.dev", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.IsTrue(_requestDetails.AdministratorMustBeLoggedOut);
        }

        [TestMethod]
        public void AdministratorMustBeLoggedOut_FrediumInstallationInProgressNoSiteCreatedYet_False()
        {
            InitRepositoryFactoryMock();
            AdministratorGroup administratorsGroup = new AdministratorGroup() { ID = 1 };
            Administrator admin = new Administrator() { ID = 666, ForceLogout = false, Group = administratorsGroup };
            AdministratorRepositoryMock.Setup(a => a.GetAdministrator(666)).Returns(admin);
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("https://fredium.dev", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.IsFalse(_requestDetails.AdministratorMustBeLoggedOut);
        }

        [TestMethod]
        public void AdministratorMustBeLoggedOut_CurrentSiteIsNullButOtherSitesAreAvailable_True()
        {
            InitRepositoryFactoryMock();
            AdministratorGroup administratorsGroup = new AdministratorGroup() { ID = 1 };
            Administrator admin = new Administrator() { ID = 666, ForceLogout = false, CurrentSite = null, Group = administratorsGroup };
            Site otherAvailableSiteA = new Site();
            Site otherAvailableSiteB = new Site();
            admin.AvailableSites.Add(otherAvailableSiteA);
            admin.AvailableSites.Add(otherAvailableSiteB);
            AdministratorRepositoryMock.Setup(a => a.GetAdministrator(666)).Returns(admin);
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("https://fredium.dev", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.IsTrue(_requestDetails.AdministratorMustBeLoggedOut);
        }

        [TestMethod]
        public void AllowContentEditing_NotSitePreview_False()
        {
            InitRepositoryFactoryMock();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("https://fredium.dev", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.IsFalse(_requestDetails.AllowContentEditing);
        }

        [TestMethod]
        public void AllowContentEditing_SiteIsPreviewButContentEditingIsNotAllowed_False()
        {
            InitRepositoryFactoryMock();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            Mock<ICmsHttpRequest> requestMock;
            requestMock = new Mock<ICmsHttpRequest>();
            requestMock.SetupGet(m => m.ApplicationPath).Returns("/");
            Uri uri = new Uri("https://fredium.dev/admin/sitepreview.aspx");
            requestMock.SetupGet(m => m.Url).Returns(uri);
            requestMock.SetupGet(m => m.QueryString).Returns(new NameValueCollection());
            requestMock.SetupGet(m => m.AllowContentEditing).Returns(false);
            _requestDetails = new RequestDetails(requestMock.Object, InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.IsFalse(_requestDetails.AllowContentEditing);
        }

        [TestMethod]
        public void AllowContentEditing_SiteIsPreviewAndContentEditingIsAllowed_True()
        {
            InitRepositoryFactoryMock();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            Mock<ICmsHttpRequest> requestMock;
            requestMock = new Mock<ICmsHttpRequest>();
            requestMock.SetupGet(m => m.ApplicationPath).Returns("/");
            Uri uri = new Uri("https://fredium.dev/admin/sitepreview.aspx");
            requestMock.SetupGet(m => m.Url).Returns(uri);
            requestMock.SetupGet(m => m.QueryString).Returns(new NameValueCollection());
            requestMock.SetupGet(m => m.AllowContentEditing).Returns(true);
            _requestDetails = new RequestDetails(requestMock.Object, InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.IsTrue(_requestDetails.AllowContentEditing);
        }

        [TestMethod]
        public void ContentTranslationVersion_QuerystringParameterExists_VersionFound()
        {
            InitRepositoryFactoryMock();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            Mock<ICmsHttpRequest> requestMock;
            requestMock = new Mock<ICmsHttpRequest>();
            requestMock.SetupGet(m => m.ApplicationPath).Returns("/");
            Uri uri = new Uri("https://fredium.dev/admin/sitepreview.aspx");
            requestMock.SetupGet(m => m.Url).Returns(uri);
            NameValueCollection queryString = new NameValueCollection();
            queryString.Add("VersionID", "44");
            requestMock.SetupGet(m => m.QueryString).Returns(queryString);
            ContentTranslationVersion ctv = new ContentTranslationVersion();
            ContentRepositoryMock.Setup(m => m.GetContentTranslationVersion(44)).Returns(ctv);
            _requestDetails = new RequestDetails(requestMock.Object, InfrastructureTestsHelper.GetIdentity(666), presenter);
            Assert.AreSame(ctv, _requestDetails.ContentTranslationVersion);
        }

        [TestMethod]
        public void FirstFolderIsLocaleCode_FirstFolderIsNoLocaleCode_False()
        {
            SetupSiteAndLocale();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("http://test.com/a/b/", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            _requestDetails.ResolveSiteAndLocale();
            Assert.IsFalse(_requestDetails.FirstFolderIsLocaleCode);
        }

        [TestMethod]
        public void FirstFolderIsLocaleCode_FirstFolderIsLocaleCode_True()
        {
            SetupSiteAndLocale();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("http://test.com/sv/b/", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            _requestDetails.ResolveSiteAndLocale();
            Assert.IsTrue(_requestDetails.FirstFolderIsLocaleCode);
        }

        [TestMethod]
        public void FirstFolderIsLocaleCode_FirstFolderIsDefaultLocaleCode_True()
        {
            SetupSiteAndLocale();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            _requestDetails = CreateMock("http://test.com/en/b/", "/", InfrastructureTestsHelper.GetIdentity(666), presenter);
            _requestDetails.ResolveSiteAndLocale();
            Assert.IsTrue(_requestDetails.FirstFolderIsLocaleCode);
        }

        private void SetupSiteAndLocale()
        {
            InitRepositoryFactoryMock();
            Site siteTest = new Site() { ID = 1, Domain = "test.com" };
            Locale localeEn = new Locale() { ID = 1, UrlCode = "en" };
            Locale localeSv = new Locale() { ID = 2, UrlCode = "sv" };
            siteTest.Locales.Add(localeEn);
            siteTest.Locales.Add(localeSv);
            siteTest.DefaultLocale = localeEn;
            localeEn.Site = siteTest;
            localeSv.Site = siteTest;
            IList<Site> sites = new List<Site> { siteTest };
            SiteRepositoryMock.Setup(m => m.GetSites()).Returns(sites);
        }

        [TestMethod]
        public void GetQueryStringValue_KeyAndValueExist_ReturnValue()
        {
            _requestDetails = CreateMock("https://fredium.dev/default.aspx?action=drinkbeer", "/", InfrastructureTestsHelper.GetIdentity(666));
            Assert.AreEqual("drinkbeer", _requestDetails.GetQueryStringValue("action"));
        }

        [TestMethod]
        public void GetQueryStringValue_KeyExistButNoValue_ReturnEmptyString()
        {
            _requestDetails = CreateMock("https://fredium.dev/default.aspx?action=", "/", InfrastructureTestsHelper.GetIdentity(666));
            Assert.AreEqual(string.Empty, _requestDetails.GetQueryStringValue("action"));
        }

        [TestMethod]
        public void GetQueryStringValue_KeyDoesntExist_ReturnEmptyString()
        {
            _requestDetails = CreateMock("https://fredium.dev/default.aspx?action=drinkbeer", "/", InfrastructureTestsHelper.GetIdentity(666));
            Assert.AreEqual(string.Empty, _requestDetails.GetQueryStringValue("status"));
        }

        private RequestDetails CreateMock(string url, string applicationPath)
        {
            Mock<ICmsIdentity> identityMock = new Mock<ICmsIdentity>();
            return CreateMock(url, applicationPath, identityMock.Object);
        }

        private RequestDetails CreateMock(string url, string applicationPath, ICmsIdentity identity)
        {
            InitRepositoryFactoryMock();
            RequestDetailsPresenter presenter = new RequestDetailsPresenter(FactoryMock.Object);
            return CreateMock(url, applicationPath, identity, presenter);
        }

        private RequestDetails CreateMock(string url, string applicationPath, ICmsIdentity identity, RequestDetailsPresenter presenter)
        {
            Mock<ICmsHttpRequest> requestMock = new Mock<ICmsHttpRequest>();
            requestMock.SetupGet(m => m.ApplicationPath).Returns(applicationPath);
            Uri uri = new Uri(url);
            requestMock.SetupGet(m => m.Url).Returns(uri);
            requestMock.SetupGet(m => m.QueryString).Returns(new NameValueCollection());
            return new RequestDetails(requestMock.Object, identity, presenter);
        }
    }
}
